﻿using System;
using System.Collections.Generic;
using System.Linq;
using ServiceStack.Redis;
using ServiceStack.Common.Web;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Threading;
using Newtonsoft;
using yq.ICache;
namespace yq.Redis
{
    /// <summary>
    /// redis缓存客户端调用类
    /// </summary>
    public partial class RedisClient<T> : yq.ICache.IClient<T> where T : class,new()
    {
        ConfigHost config;
        public RedisClient(ConfigHost config)
        {
            this.config = config;
        }

        #region 内部方法


        ///// <summary>
        ///// 获取写站点client
        ///// </summary>
        ///// <param name="keyName"></param>
        ///// <returns></returns>
        //private IRedisClient GetWriteClient()
        //{
        //    //正式部分
        //    IRedisClient client = RedisManagers.GetClientManager(config).GetClient();

        //    return client;
        //}

        ///// <summary>
        ///// 获取读站点client
        ///// </summary>
        ///// <param name="keyName"></param>
        ///// <returns></returns>
        //private IRedisClient GetReadClient()
        //{
        //    //正式部分
        //    IRedisClient client = RedisManagers.GetClientManager(config).GetReadOnlyClient();
        //    return client;
        //}

        ///// <summary>
        ///// 处理只读服务失效
        ///// </summary>
        ///// <param name="ex"></param>
        ///// <param name="host"></param>
        ///// <param name="port"></param>
        //private static void FindReadException(Exception ex, string host, int port)
        //{
        //    if (ex is RedisException)
        //    {
        //        //先检测该请求是否已经在失效节点中
        //        string key = GetKey(host, port);
        //        //如果请求处理的节点已经存在,则不需要再处理了
        //        if (ExceptionReadLists.ContainsKey(key)) return;

        //        //开始处理
        //        EndPoint info = ClientManager.RemoveReadEndPoint(host, port);
        //        if (info != null)
        //        {
        //            //添加到失效信息中
        //            ExceptionReadLists.Add(key, info);

        //            //起异步线程在一段时间内重复检测
        //            Task task = new Task(() => { TestEndPoint(info); });
        //            task.Start();
        //        }
        //    }
        //}


        /// <summary>
        /// 根据对象类型获取其全称作为HASH/List/Set表的主ID
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        private string GetEntryId()
        {
            return config.FullName;
        }

        /// <summary>
        /// 根据对象类型获取其全称作为HASH/List/Set表的主ID
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private static string GetEntryId(Type type)
        {
            return type.FullName;
        }


        #endregion

        #region 针对Hash表的操作

        #region 写对象
        /// <summary>
        /// 存储对象到缓存中
        /// </summary>
        /// <param name="key">需要写入的主键,一般为对象ID值,必须是文本/数字等对象</param>
        /// <param name="value">对象</param>
        public bool HSet(string key, T value)
        {
            Func<IRedisClient, bool> fun = (IRedisClient client) =>
            {
                string hashId = GetEntryId();
                string ser = Newtonsoft.Json.JsonConvert.SerializeObject(value);
                return client.SetEntryInHash(hashId, key.ToString(), ser);
            };

            return TryRedisWrite<bool>(fun);
        }


        /// <summary>
        /// 一次性写多个对象
        /// 无返回值
        /// </summary>
        /// <param name="values">对象</param>
        public void HSet(Dictionary<string, T> values)
        {
            //生成新列表,以便一次性写入
            Dictionary<string, string> dics = new Dictionary<string, string>();
            //循环旧列表转换为文本
            foreach (string key in values.Keys)
            {
                dics.Add(key.ToString(), Newtonsoft.Json.JsonConvert.SerializeObject(values[key]));
            }

            HSet(dics);
        }


        /// <summary>
        /// 一次性写多个对象
        /// 无返回值
        /// </summary>
        /// <param name="dics">对象</param>
        public void HSet(Dictionary<string, string> dics)
        {
            Func<IRedisClient, bool> fun = (IRedisClient client) =>
            {
                string hashId = GetEntryId();

                //调用写入
                client.SetRangeInHash(hashId, dics);

                return false;
            };

            TryRedisWrite<bool>(fun);
        }


        /// <summary>
        /// 一次性写入多个对象
        /// </summary>
        /// <param name="keys">每个对象对应的KEY值</param>
        /// <param name="values">对象列表</param>
        public void HSet(IList<string> keys, IList<T> values)
        {
            Func<IRedisClient, bool> fun = (IRedisClient client) =>
            {
                //生成新列表,以便一次性写入
                Dictionary<string, string> dics = new Dictionary<string, string>();
                int count = keys.Count;

                //循环旧列表转换为文本
                for (int i = 0; i < count; i++)
                {
                    dics.Add(keys[i].ToString(), Newtonsoft.Json.JsonConvert.SerializeObject(values[i]));
                }

                string hashId = GetEntryId();
                //调用写入
                client.SetRangeInHash(hashId, dics);
                return false;
            };

            TryRedisWrite<bool>(fun);
        }

        /// <summary>
        /// 存储对象到缓存中(如果缓存中已经有了则不写入;如果缓存没有才写入)
        /// </summary>
        /// <param name="key">需要写入的主键,一般为对象ID值,必须为文本数字等非传址对象</param>
        /// <param name="value">对象</param>
        public bool HSetIfNotExists(string key, T value)
        {
            Func<IRedisClient, bool> fun = (IRedisClient client) =>
            {
                string hashId = GetEntryId();
                string ser = Newtonsoft.Json.JsonConvert.SerializeObject(value);
                return client.SetEntryInHashIfNotExists(hashId, key.ToString(), ser);
            };
            return TryRedisWrite<bool>(fun);
        }

        /// <summary>
        /// 移除指定的记录
        /// </summary>
        /// <param name="key">需要移除的主键,一般为对象ID值</param>
        /// <returns></returns>
        public bool HRemove(string key)
        {
            Func<IRedisClient, bool> fun = (IRedisClient client) =>
             {
                 string hashId = GetEntryId();

                 return client.RemoveEntryFromHash(hashId, key.ToString());
             };

            return TryRedisWrite<bool>(fun);
        }


        /// <summary>
        /// 移除指定类型的所有数据
        /// </summary>
        /// <param name="typeName">实体类型</param>
        /// <returns></returns>
        public bool HRemoveAll()
        {
           Func<IRedisClient, bool> fun = (IRedisClient client) =>
           {
               string typeName = GetEntryId();

               return client.Remove(typeName);
           };

            return TryRedisWrite<bool>(fun);
        }


        /// <summary>
        /// 批量移除指定的记录,无返回值
        /// </summary>
        /// <typeparam name="T">对象类别</typeparam>
        /// <param name="keys">需要移除的主键,一般为对象ID值</param>
        /// <returns></returns>
        public void HRemove(IList<string> keys)
        {
            Func<IRedisClient, bool> fun = (IRedisClient client) =>
             {
                 string hashId = GetEntryId();

                 foreach (string key in keys)
                 {
                     client.RemoveEntryFromHash(hashId, key.ToString());
                 }

                 return false;
             };

            TryRedisWrite<bool>(fun);
        }

        #endregion 写对象

        #region 获取对象

        /// <summary>
        /// 根据ID获取指定对象
        /// </summary>
        /// <param name="key">需要获取的主键,一般为对象ID值</param>
        /// <returns></returns>
        public T HGet(string key)
        {
            if (key == null)
            {
                return default(T);
            }

            Func<IRedisClient, T> fun = (IRedisClient client) =>
             {
                 string ser = "";
                 string hashId = GetEntryId();
                 ser = client.GetValueFromHash(hashId, key.ToString());
                
                 return ser==null?new T(): Newtonsoft.Json.JsonConvert.DeserializeObject<T>(ser);
             };

            return TryRedisRead(fun);
        }

        /// <summary>
        /// 根据ID集合获取指定对象集合
        /// </summary>
        /// <typeparam name="T">对象类别</typeparam>
        /// <param name="keys">需要获取的主键,一般为对象ID值</param>
        /// <returns></returns>
        public IList<T> HGet(IList<string> keys)
        {
            return HGet(keys.ToArray());
        }


        /// <summary>
        /// 根据ID集合获取指定对象集合
        /// </summary>
        /// <param name="keys">需要获取的主键,一般为对象ID值</param>
        /// <returns></returns>
        public IList<T> HGet(string[] keys)
        {

            Func<IRedisClient, IList<T>> fun = (IRedisClient client) =>
            {
                IList<string> tmpLists = new List<string>();
                string hashId = GetEntryId();

                tmpLists = client.GetValuesFromHash(hashId, keys);

                IList<T> lists = new List<T>();
                if (tmpLists.Count > 0)
                {
                    foreach (string value in tmpLists)
                    {
                        if (string.IsNullOrEmpty(value) == false)
                        {
                            lists.Add(Newtonsoft.Json.JsonConvert.DeserializeObject<T>(value));
                        }
                    }
                }

                return lists;
            };

            return TryRedisRead(fun);
        }

        /// <summary>
        /// 获取指定对象的所有记录(IList)
        /// </summary>
        /// <returns></returns>
        public IList<T> HGetAllValues()
        {
            string hashId = GetEntryId();
            IList<string> tmpLists = HGetAllValues(hashId);

            IList<T> lists = new List<T>();
            if (tmpLists.Count > 0)
            {
                foreach (string value in tmpLists)
                {
                    lists.Add(Newtonsoft.Json.JsonConvert.DeserializeObject<T>(value));
                }
            }

            return lists;
        }


        /// <summary>
        /// 获取指定对象的所有记录(IList)
        /// </summary>
        /// <param name="typeName">类别名称</param>
        /// <returns></returns>
        private IList<string> HGetAllValues(string typeName)
        {
            Func<IRedisClient, IList<string>> fun = (IRedisClient client) =>
            {
                string hashId = typeName;
                IList<string> lists = new List<string>();
                return client.GetHashValues(hashId);
            };

            return TryRedisRead(fun);
        }

        /// <summary>
        /// 获取指定对象的所有keys(键值)记录(IList)
        /// </summary>
        /// <returns></returns>
        public IList<string> HGetAllKeys()
        {
            Func<IRedisClient, IList<string>> fun = (IRedisClient client) =>
             {
                 IList<string> lists = new List<string>();
                 string hashId = GetEntryId();

                 lists = client.GetHashKeys(hashId);

                 return lists;
             };

            return TryRedisRead(fun);
        }

        /// <summary>
        /// 获取指定对象的所有值,返回ID与value的集合
        /// </summary>
        /// <typeparam name="T">对象类别</typeparam>
        /// <returns></returns>
        public Dictionary<string, T> HGetAll()
        {
            Func<IRedisClient, Dictionary<string, T>> fun = (IRedisClient client) =>
            {
                string hashId = GetEntryId();
                Dictionary<string, string> tmpDics = new Dictionary<string, string>();
                tmpDics = client.GetAllEntriesFromHash(hashId);
                Dictionary<string, T> lists = new Dictionary<string, T>();
                if (tmpDics.Count > 0)
                {
                    foreach (string key in tmpDics.Keys)
                    {
                        lists.Add(key, Newtonsoft.Json.JsonConvert.DeserializeObject<T>(tmpDics[key]));
                    }
                }

                return lists;
            };

            return TryRedisRead(fun);
        }

        /// <summary>
        /// 获取指定对象记录总数量
        /// </summary>
        /// <returns></returns>
        public int HGetCount()
        {
            Func<IRedisClient, int> fun = (IRedisClient client) =>
            {
                string className = GetEntryId();

                return client.GetHashCount(className);
            };

            return TryRedisRead(fun);
        }

        /// <summary>
        /// 判断指定的记录是否已经存在缓存中
        /// </summary>
        /// <param name="key">需要判断的主键,一般为对象ID值</param>
        /// <returns></returns>
        public bool HashContains(string key)
        {
            Func<IRedisClient, bool> fun = (IRedisClient client) =>
            {
                string hashId = GetEntryId();

                return client.HashContainsEntry(hashId, key.ToString());
            };

            return TryRedisRead(fun);
        }

        #endregion 获取对象

        #endregion 针对Hash表的操作

        #region 针对常规Key/Value方式的操作
        #region 写对象
        /// <summary>
        /// 以Key/Value的形式存储对象到缓存中
        /// </summary>
        /// <typeparam name="T">对象类别</typeparam>
        /// <param name="key">需要写入的主键,一般为对象ID值,必须是文本/数字等对象</param>
        /// <param name="value">对象</param>
        public bool KSet(string key, T value)
        {
            Func<IRedisClient, bool> fun = (IRedisClient client) =>
            {
                string hashId = GetEntryId();
                client.SetEntry(key, Newtonsoft.Json.JsonConvert.SerializeObject(value));
                return true;
            };

            return TryRedisWrite(fun);
        }

        /// <summary>
        /// 以Key/Value的形式存储对象到缓存中
        /// </summary>
        /// <typeparam name="T">对象类别</typeparam>
        /// <param name="key">需要写入的主键,一般为对象ID值,必须是文本/数字等对象</param>
        /// <param name="value">对象</param>
        /// <param name="expiresTime">过期时间</param>
        public bool KSet(string key, T value, DateTime expiresTime)
        {
            string hashId = GetEntryId();
            KSet(hashId, key.ToString(), Newtonsoft.Json.JsonConvert.SerializeObject(value), expiresTime - DateTime.Now);

            return true;
        }


        /// <summary>
        /// 以Key/Value的形式存储对象到缓存中
        /// </summary>
        /// <typeparam name="T">对象类别</typeparam>
        /// <param name="key">需要写入的主键,一般为对象ID值,必须是文本/数字等对象</param>
        /// <param name="value">对象</param>
        /// <param name="expiresIn">过期时间</param>
        public bool KSet(string key, T value, TimeSpan expiresIn)
        {
            string hashId = GetEntryId();
            KSet(hashId, key.ToString(), Newtonsoft.Json.JsonConvert.SerializeObject(value), expiresIn);

            return true;
        }


        /// <summary>
        /// 写入key/value值
        /// </summary>
        /// <param name="typeName"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expireIn"></param>
        private void KSet(string typeName, string key, string value, TimeSpan expireIn)
        {
            Func<IRedisClient, bool> fun = (IRedisClient client) =>
            {

                if (expireIn == System.TimeSpan.MinValue)
                {
                    client.SetEntry(key, value);
                }
                else
                {
                    client.SetEntry(key, value, expireIn);
                }
                return false;
            };

            TryRedisWrite(fun);
        }

        /// <summary>
        /// 以Key/Value的形式存储对象到缓存中
        /// </summary>
        /// <typeparam name="T">对象类别</typeparam>
        /// <param name="value">要写入的集合</param>
        public void KSet(Dictionary<string, T> value)
        {
            Func<IRedisClient, bool> fun = (IRedisClient client) =>
            {
                string hashId = GetEntryId();
                client.SetAll<T>(value);
                return true;
            };

            TryRedisWrite(fun);
        }


        /// <summary>
        /// 移除Key/Value的对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool KRemove(string key)
        {
            Func<IRedisClient, bool> fun = (IRedisClient client) =>
            {
                string hashId = GetEntryId();
                return client.Remove(key);
            };

            return TryRedisWrite(fun);
        }

        /// <summary>
        /// 移除Key/Value的对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="keys"></param>
        /// <returns></returns>
        public void KRemove(IList<string> keys)
        {
            Func<IRedisClient, bool> fun = (IRedisClient client) =>
            {
                string hashId = GetEntryId();
                client.RemoveAll(keys);
                return false;
            };

            TryRedisWrite(fun);
        }

        #endregion 写对象
        #region 读对象
        /// <summary>
        /// 读取Key/Value值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public T KGet(string key)
        {
            Func<IRedisClient, T> fun = (IRedisClient client) =>
            {
                string hashId = GetEntryId();
                string ser = "";
                ser = client.GetValue(key.ToString());
                if (string.IsNullOrEmpty(ser) == false)
                {
                    return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(ser);
                }
                else
                {
                    return default(T);
                }
            };
            return TryRedisRead(fun);
        }

        /// <summary>
        /// 读取Key/Value值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="keys"></param>
        /// <returns></returns>
        public Dictionary<string, T> KGet(IList<string> keys)
        {
            Func<IRedisClient, Dictionary<string, T>> fun = (IRedisClient client) =>
             {
                 string hashId = GetEntryId();
                 return (Dictionary<string, T>)client.GetAll<T>(keys);
             };

            return TryRedisRead(fun);
        }

        /// <summary>
        /// 读取Key/Value值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="keys"></param>
        /// <returns></returns>
        public IList<T> KGetList(IList<string> keys)
        {
            Dictionary<string, T> dics = KGet(keys);
            return dics.Values.ToList();
        }

        /// <summary>
        /// 返回根据条件查找到的KEY对象列表        
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pattern"></param>
        /// <returns></returns>
        public IList<string> KSearchKeys(string pattern)
        {
            Func<IRedisClient, IList<string>> fun = (IRedisClient client) =>
            {
                string hashId = GetEntryId();
                return client.SearchKeys(pattern);
            };

            return TryRedisRead(fun);
        }

        /// <summary>
        /// 返回根据条件查找到的value对象列表        
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pattern"></param>
        /// <returns></returns>
        public IList<T> KSearchValues(string pattern)
        {
            Func<IRedisClient, IList<T>> fun = (IRedisClient client) =>
            {
                string hashId = GetEntryId();
                IList<string> keys = new List<string>();

                //先查找KEY
                keys = client.SearchKeys(pattern);

                if (keys != null && keys.Count > 0)
                {
                    //再直接根据key返回对象列表
                    Dictionary<string, T> dics = (Dictionary<string, T>)client.GetAll<T>(keys);

                    return dics.Values.ToList<T>();
                }
                else
                {
                    return new List<T>();
                }

            };

            return TryRedisRead(fun);
        }

        #endregion 读对象

        #endregion 针对常规Key/Value方式的操作

        public bool HashRefreshDelete(string fullname, string key)
        {
            Func<IRedisClient, bool> fun = (IRedisClient client) =>
            {
                return client.RemoveEntryFromHash(fullname, key.ToString());
            };

            return TryRedisWrite<bool>(fun);
        }


        public void HashRefreshLoad(string fullname, string key, object value)
        {
            Func<IRedisClient, bool> fun = (IRedisClient client) =>
            {
                string ser = Newtonsoft.Json.JsonConvert.SerializeObject(value);
                return client.SetEntryInHash(fullname, key.ToString(), ser);
            };

             TryRedisWrite<bool>(fun);
        }

        public bool HashRefreshDelete(string fullname)
        {
            Func<IRedisClient, bool> fun = (IRedisClient client) =>
            {
                return client.Remove(fullname);
            };

            return TryRedisWrite<bool>(fun);
        }
    }

}